package com.bgh.dynobot;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Random;
import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;


//public class TimedRun extends Activity implements SensorListener, OnClickListener {
public class TimedRun extends Activity implements OnClickListener {
	
	private SensorManager mSensorManager;
	private Button startButton, stopResetButton;
	private float x, y, z = 0f;
	private TextView speedTV,timeTV, statusTV;
	private TextView feet60TV, feet330TV, feet660TV, feet1000TV;
	double maxGs = 0;
    private long lastUpdate, runStartTime = -1;
    boolean inTimedRun = false;
    boolean timing = false;
	long lastTime;
	double distance, velocity, oldDistance, oldVelocity, runTimeSeconds = 0;
	private View graphView;
	private View progressView;
	String currentVehicle = null;
	int currentVehicleID = 0;
	int run_id = 0;
	double xSquared, ySquared, zSquared, gSquared, accel = 0;
	long now, runTime, timeDiffMillis = 0;
    double timeDiffSeconds = 0;
    double time_60, time_330, time_660, time_1000, time_et = 0;
	
	
	private Bitmap  graphBitmap;
    private Paint   graphPaint = new Paint();
    private Canvas  graphCanvas = new Canvas();
    private float   graphYOffset, graphWidth, graphHeight = 0f;
    private double secondInterval, velocityInterval, gInterval;
    private float lastVelX, lastVelY = 0f;
    private float lastGX, lastGY = 0f;
    
    
    private Bitmap  progressBitmap;
    private Paint   progressPaint = new Paint();
    private Canvas  progressCanvas = new Canvas();
    private float   progressWidth, progressHeight, blockWidth = 0f;
    
    private static final double GRAPH_SECONDS = 20;
    private static final double GRAPH_MAX_VELOCITY = 70;
    private static final double GRAPH_MAX_G = 4;
    private static final double PROGRESS_BLOCKS = 40;
    private static final double ONE_MILE = 402.336;
    private static final double FEET_60 = 18.288;
    private static final double FEET_330 = 100.584;
    private static final double FEET_660 = 201.168;
    private static final double FEET_1000 = 304.8;
    
    private static final float GRAPH_LINE_WIDTH = 3;
    
	
    private ArrayList<double[]> runDataArrayList = new ArrayList<double[]>();
    
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);   
        setContentView(R.layout.timed_run);         
        
        graphView = new GraphView(this);
        LinearLayout l = (LinearLayout) findViewById(R.id.graph_layout);
        l.addView(graphView);
        
        progressView = new ProgressView(this);
        LinearLayout l2 = (LinearLayout) findViewById(R.id.progress_layout);
        l2.addView(progressView);
        
        Typeface LCDface=Typeface.createFromAsset(getAssets(), "lcd_font_mono.ttf");
        //vehicleTV = (TextView) findViewById(R.id.vehicleName);
        timeTV = (TextView) findViewById(R.id.time);
        timeTV.setTypeface(LCDface);          
        timeTV.setTextSize(40);
        speedTV = (TextView) findViewById(R.id.speed);
        speedTV.setTypeface(LCDface);
        speedTV.setTextSize(40);
        
        feet60TV = (TextView) findViewById(R.id.feet60);
        feet60TV.setTypeface(LCDface);          
        feet60TV.setTextSize(20);
        feet330TV = (TextView) findViewById(R.id.feet330);
        feet330TV.setTypeface(LCDface);          
        feet330TV.setTextSize(20);
        feet660TV = (TextView) findViewById(R.id.feet660);
        feet660TV.setTypeface(LCDface);          
        feet660TV.setTextSize(20);
        feet1000TV = (TextView) findViewById(R.id.feet1000);
        feet1000TV.setTypeface(LCDface);          
        feet1000TV.setTextSize(20);
        //distanceTV = (TextView) findViewById(R.id.distance);
        //GsTV = (TextView) findViewById(R.id.Gs);
        //maxGsTV = (TextView) findViewById(R.id.maxGs);
        statusTV = (TextView) findViewById(R.id.status);
        startButton = (Button) findViewById(R.id.start);
        startButton.setOnClickListener(this);
        stopResetButton = (Button) findViewById(R.id.stopReset);
        stopResetButton.setOnClickListener(this);
        
        PreferenceManager.setDefaultValues(this, R.xml.preferences, false);
 		SharedPreferences appPreferences = PreferenceManager.getDefaultSharedPreferences(this);
 		currentVehicle = appPreferences.getString("current_vehicle", "Default vehicle");
 		currentVehicleID = appPreferences.getInt("current_vehicle_id",0);
 		//vehicleTV.setText(currentVehicle);
 		
 	    // Set up the accelerometer reading
 	    mSensorManager = (SensorManager)getSystemService (Context.SENSOR_SERVICE);
 	    // Get the list of all sensors, and find the accelerometer within
 	    List<Sensor> sensorList = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);

 	    mSensorManager.registerListener(mSensorListener, sensorList.get(0), SensorManager.SENSOR_DELAY_UI);

    }

    //Accelerometer
 	private final SensorEventListener mSensorListener = new SensorEventListener() {


	    public void onAccuracyChanged(Sensor sensor, int accuracy) {
	            // TODO Auto-generated method stub
	
	    }
	
	    public void onSensorChanged(SensorEvent event) {
	    	
	    	DecimalFormat f = new DecimalFormat("0.00");
	 	   
			x = event.values[0];
			y = event.values[1];
			z = event.values[2];		

			if (inTimedRun) {
				xSquared = Math.pow(x, 2);
		    	ySquared = Math.pow(y, 2);
		    	zSquared = Math.pow(z, 2);
		    	gSquared = Math.pow(SensorManager.GRAVITY_EARTH, .5);
		    	accel = Math.pow(xSquared + ySquared + zSquared + gSquared, .5);
		    	
		    	if(accel > 1.0 & timing == false){
		    		timing = true;
		    		runStartTime = System.currentTimeMillis();
		    		lastTime = runStartTime;
		    		statusTV.setText("Timing...");
					//statusTV.setTextColor(Color.RED);
		    	}
		    	
		    	now = System.currentTimeMillis();
	            runTime = now - runStartTime;
	            timeDiffMillis = (now - lastTime);
	            timeDiffSeconds = (double)timeDiffMillis / 1000;
		    	
		    	if(timing){
		    		
		    		//Random generator = new Random();
		    		//int randomIndex = generator.nextInt( 3 ) + 3;
		    		
		    		//accel = randomIndex;
		    		
		    		//oldVelocity = velocity;
			    	velocity = (accel);
			    	//velocity = velocity + (accel * timeDiffSeconds);
			    	
			    	//distance = distance + (velocity * timeDiffSeconds) + (.5 * (accel * Math.pow(timeDiffSeconds, 2)));			    	
			    	distance = distance + (.5 * accel * Math.pow(timeDiffSeconds, 2)) + (velocity * timeDiffSeconds);

			    	
				    runTimeSeconds = (double)runTime / 1000;
				    
				    if(accel/SensorManager.GRAVITY_EARTH > maxGs){
				    	maxGs = accel/SensorManager.GRAVITY_EARTH;
				    	//maxGsTV.setText(f.format(maxGs) + "Gs");
				    }
				    
				  //Check if run is finished
					if(distance > ONE_MILE){
						inTimedRun = false;
						timing = false;
						time_et = runTimeSeconds;
						statusTV.setText("Done");
						statusTV.setTextColor(Color.BLACK);
						stopResetButton.setText("RESET");
						//addRunToDB();
					}else if(distance > FEET_1000 && time_1000 == 0){
						time_1000 = runTimeSeconds;
						feet1000TV.setText(f.format(time_1000));
					}else if(distance > FEET_660 && time_660 == 0){
						time_660 = runTimeSeconds;
						feet660TV.setText(f.format(time_660));
					}else if(distance > FEET_330 && time_330 == 0){
						time_330 = runTimeSeconds;
						feet330TV.setText(f.format(time_330));
					}else if(distance > FEET_60 && time_60 == 0){
						time_60 = runTimeSeconds;
						feet60TV.setText(f.format(time_60));
					}
				    
				    //Put the run data into an array and then store
				    
				    /*
					 0 - Time
					 1 - Distance
					 2 - Acceleration
					 3 - Velocity
					 * */
				    
					//double[] runData =  {runTimeSeconds, distance, accel, velocity};
				    //runDataArrayList.add(runData);
					
					if (now - lastTime > 100) {
						timeTV.setText(f.format(runTimeSeconds));
						speedTV.setText(f.format((velocity/1000) * 60 * 60));
						
											
						synchronized (this) {
				            if (graphBitmap != null) {
				                final Canvas canvas = graphCanvas;
				                final Paint paint = graphPaint;
		                        paint.setColor(Color.BLACK);

								paint.setAlpha(255);
								paint.setStrokeWidth(GRAPH_LINE_WIDTH);
		                        canvas.drawLine(lastVelX, lastVelY, 
		                        		(float) (runTimeSeconds * secondInterval),  
		                        		(float) (graphHeight - (velocity * velocityInterval)), paint);
		                        
		                        lastVelX = (float) (runTimeSeconds * secondInterval);
		                        lastVelY = (float) (graphHeight - (velocity * velocityInterval));
		                        
				                graphView.invalidate();
				                progressView.invalidate();
				                
				                lastTime = now;
				            }
						}
					}						
		        }
			}
	    }
 	}; 

	
	
	private void addRunToDB(){
		
		statusTV.setText("Storing data");
		final Calendar cal = Calendar.getInstance(); 
		
		SimpleDateFormat formatter = new SimpleDateFormat("E, dd MMM yyyy HH:mm");
		String dateFormatted = formatter.format(cal.getTime()); 
		
		DynoDbAdapter DbHelper = new DynoDbAdapter(this);
        DbHelper.open();
                
        //Create a new run
        DbHelper.insertRun(currentVehicleID, dateFormatted);
        
        run_id = 0;
        Cursor c = DbHelper.fetchLastRunID();
        if (c.moveToFirst()) {
        	run_id = c.getInt(0);
        }
        c.close();
        //ThreadedDbHelper.insertTime(run_id, runDataArrayList);
        //DbHelper.close();
        
        statusTV.setText("Storing results..");
        /*Thread t = new Thread() {
            public void run() {
                while (true) {
                	DynoDbAdapter ThreadedDbHelper = new DynoDbAdapter(TimedRun.this);
                	ThreadedDbHelper.open();
                	ThreadedDbHelper.insertTime(run_id, runDataArrayList);
                	ThreadedDbHelper.close();
                	//Toast.makeText(TimedRun.this, "Timed run saved", Toast.LENGTH_LONG).show();
                }

            }
        };
        t.start();*/
        DbHelper.insertTime(run_id, runDataArrayList);
        DbHelper.close();
        
        statusTV.setText("Done");
	}
	
	public void onClick(View v) {
		if (v == startButton) {
			inTimedRun = true;
			statusTV.setText("Ready...");
			//statusTV.setTextColor(Color.GREEN);
			stopResetButton.setText("STOP");
		}
		
		if (v == stopResetButton) {
			if(inTimedRun || timing){
				inTimedRun = false;
				timing = false;
				statusTV.setText("Done");
				statusTV.setTextColor(Color.BLACK);
				stopResetButton.setText("RESET");
			}else{
				inTimedRun = false;
				velocity = 0;
				runStartTime = 0;
				distance = 0;
				timeTV.setText("0:00");
				speedTV.setText("0:00");
				statusTV.setText("Dynobot");
				feet60TV.setText("0:00");
				feet330TV.setText("0:00");
				feet660TV.setText("0:00");
				feet1000TV.setText("0:00");
				//statusTV.setTextColor(Color.BLACK);
				stopResetButton.setText("RESET");
			}
		}
	}
	
	private class GraphView extends View
    {
        public GraphView(Context context) {
            super(context);
        }
        
        public void resetGraph(int w, int h){
        	graphBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
            graphCanvas.setBitmap(graphBitmap);
            graphCanvas.drawColor(0xFFA3DB51);
            graphPaint.setColor(0xFFABBE87);
            graphCanvas.drawLine(0, graphYOffset, graphWidth, graphYOffset, graphPaint);
            for(int i = 1; i < 20; i++){
            	graphCanvas.drawLine((float)(i * secondInterval), 0, (float)(i * secondInterval), graphHeight, graphPaint);
            }
        }
        
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            
            graphYOffset = h * 0.5f;
            secondInterval = w/GRAPH_SECONDS;
            velocityInterval = h/GRAPH_MAX_VELOCITY;
            gInterval = h/GRAPH_MAX_G;
       
            graphWidth = w;
            graphHeight = h;
            lastVelY = graphHeight;
            resetGraph(w,h);
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            synchronized (this) {
                if (graphBitmap != null) {
                   canvas.drawBitmap(graphBitmap, 0, 0, null);
                }
            }
        }
    }
	
	private class ProgressView extends View
    {
        public ProgressView(Context context) {
            super(context);
        }
        
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        	/*progressBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
        	progressCanvas.setBitmap(progressBitmap);
        	progressCanvas.drawColor(0xFFFFFFFF);   */    
        	progressWidth = w;
        	progressHeight = h;      
        	blockWidth = (float) ((progressWidth - PROGRESS_BLOCKS)/PROGRESS_BLOCKS);
        	progressPaint.setStrokeWidth(1);
            super.onSizeChanged(w, h, oldw, oldh);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            synchronized (this) {
            	for(int i = 0;i<PROGRESS_BLOCKS;i++){
            		if(distance > (ONE_MILE/PROGRESS_BLOCKS) * i){
            			progressPaint.setColor(Color.BLACK);
            			canvas.drawRect(i*(blockWidth+1), 0, (i*(blockWidth+1)) + blockWidth, progressHeight, progressPaint);
            		}else{
            			progressPaint.setColor(0xFFABBE87);	
            			canvas.drawRect(i*(blockWidth+1), 0, (i*(blockWidth+1)) + blockWidth, progressHeight, progressPaint);
            		}            		
            	}
            }        	
        }
    }

	public void onAccuracyChanged(Sensor arg0, int arg1) {
		// TODO Auto-generated method stub
		
	}

	public void onSensorChanged(SensorEvent event) {
		// TODO Auto-generated method stub
		
	}
}